import {safeStringify} from '../safeStringify';
import {xhr} from '../ajax/xhr';
import safeJson from "../safeJson";
import simpleForEach from "../simpleForEach";


let count = 0;
const genKey = (key) => {
    const now = (new Date).getTime();
    return `${key}__${now}_${count++}`
};
const getSyncItem = (key, data, first) => {
    const regKey = new RegExp(`^${key}__\\d+_\\d+(__full)?`);
    const rst = [];
    let item;
    let resultItem;
    for (let k in data) {
        if (!regKey.test(k)) {
            continue;
        }
        item=safeJson(data[k]);
        resultItem={
            key:k,
            val:item,
            raw:data[k]
        };
        if (first && first(item, k)) {
            return resultItem;
        }
        rst.push(resultItem);
    }
    return first?null:rst;
};
const getFirstItem = (key, first=()=>true) => {
    return getSyncItem(key, localStorage, first);
};
const replaceLocalStorageKey=(key,newKey)=>{
    localStorage.setItem(newKey,localStorage.getItem(key));
    localStorage.removeItem(key);
};
const regFull=/__full$/;
export const EmptyResult = {};
export const syncToLocalStorageRaw = ({
    key,
    getData,
    done,
    interval = 5000,
    concatData,
    checkConcat,
    maxSize = 8000
} = {}) => {

    const save = () => {
        let data = getData();
        if (data === EmptyResult) {
            return;
        }
        let _key, item;
        if (checkConcat) {
            item = getFirstItem(key, (item,key) => {
                if(regFull.test(key)){
                    return false;
                }
                if (!checkConcat(data,item)) {
                    return false;
                }
                const saveData = safeStringify(data.data);
                const newLen=item.raw.length + saveData.length;
                console.log('合并后长度',newLen);
                if(newLen >= maxSize) {
                    replaceLocalStorageKey(key,key+'__full');
                    return false;
                }
                return true;
            });
        }
        if (!item) {
            _key = genKey(key);
        } else {
            _key = item.key;
            data = concatData(data,item.val);
        }

        localStorage.setItem(_key, safeStringify(data));
        done && done();
    };
    //定时保存数据到localStorage中
    let handler = setInterval(save, interval);
    const cancel = () => {
        clearInterval(handler);
    };
    return {
        save,
        cancel
    }
};

export const syncToLocalStorage = ({
    version='1.0.0',
    getData,
    checkConcat,
    ...other
} = {}) => {
    const _getData=()=>{
        const data=getData();
        data.__version=version;
        return data;
    };
    const _checkConcat=(data,oldData)=>{
        if(!oldData.__version!==data.__version){
            return false;
        }
        return checkConcat(data,oldData);
    };
    return syncToLocalStorageRaw({
        ...other,
        getData:_getData,
        checkConcat:_checkConcat
    })
};

export const cleanOtherVersion=(key,version)=>{
    const items=getSyncItem(key,localStorage);
    simpleForEach(items,({key='',val}={})=>{
        if(key&&(val.__version!==version)){
            localStorage.removeItem(key)
        }
    });
};


const toServer=(item)=>{
    const {requestArgs = {}, data} = item.val;
    const itemKey=item.key;
    if (!requestArgs.url || !data) {
        localStorage.removeItem(itemKey);
        return;
    }
    return xhr({
        ...requestArgs,
        body: data
    }).then(() => {
        localStorage.removeItem(itemKey);
    });
};
const syncToServerRaw = ({
    key,
    done,
    interval = 10000,
    version='',
    retryRemove=2
} = {}) => {
    const errItems={};
    const getItem=()=>{
        return getFirstItem(key,(item)=>{
            if(version&&item.__version!==version){
                return false;
            }
            return true;
        })
    };
    const errHandler=(itemKey)=>{
        if(itemKey in errItems){
            errItems[itemKey]++;
            if(errItems[itemKey]>retryRemove){
                localStorage.removeItem(itemKey);
                delete errItems[itemKey];
            }
            return;
        }
        errItems[itemKey]=1;
    };

    const sync=()=>{
        const item=getItem();
        const itemKey=item.key;
        return toServer(item)
            .catch(()=>{
                errHandler(itemKey);
            });
    };
    let handler = setInterval(sync, interval);
    const cancel = () => {
        clearInterval(handler);
    };
    return {
        sync,
        cancel
    }
};
export const syncToServer = ({
    version='1.0.0',
    cleanOldVersion=false,
    key,
    ...other
} = {}) => {
    if(cleanOldVersion){
        cleanOtherVersion(key,version);
    }
    return syncToServerRaw({
        key,
        version,
        ...other
    });
};
